/*
 * IMP alloc interface.
 *
 * Copyright (C) 2014 Ingenic Semiconductor Co.,Ltd
 * Author: Aeolus <weiqing.yan@ingenic.com>
 */

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <fcntl.h>
#include <semaphore.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/prctl.h>
#include <linux/videodev2.h>
#include <linux/v4l2-mediabus.h>
#include <sys/types.h>
#include <sys/stat.h>

#include <sys/mman.h>
#include <imp/imp_log.h>
#include <imp/imp_common.h>
#include <imp/imp_common.h>
#include "../../include/system/imp_v4l2.h"
#include "alloc_manager.h"
#include "alloc_common.h"
#ifdef DMALLOC
#include <imp/dmalloc.h>
#endif
#include "../../faststart_config.h"
#define TAG "IMP Alloc APIs"

static Alloc g_alloc;

void IMP_Alloc_Dump();
void IMP_Alloc_Dump_To_File();

#if 1/*ZRT_Platform*/ && FASTSTART_EN
/*For Zeratul*/

enum{
    MAIN_SENSOR_CHN0 = 0,
    MAIN_SENSOR_CHN1,
    MAIN_SENSOR_CHN2,
    SEC_SENSOR_CHN3,
    SEC_SENSOR_CHN4,
    SEC_SENSOR_CHN5,
    CHN_MAX,
};
static int g_VBMPoolx_alloc_flag[6] = {0,0,0,0,0,0};
static IMPAlloc g_VBMPoolx_alloc[6] = {0,0,0,0,0,0};

static uint32_t ncubuf_len=0;
static int g_ncubuf_alloc_flag=0;
static int g_ncu_1_buf_alloc_flag=0;
static int g_wdrbuf_alloc_flag=0;
static int g_vpuBs_alloc_flag=0;
static IMPAlloc g_ncubuf_alloc;
static IMPAlloc g_ncu_1_buf_alloc;
static IMPAlloc g_wdrbuf_alloc;
static IMPAlloc g_vpuBs_alloc;

extern unsigned int g_sensor_width;
extern unsigned int g_sensor_height;

int cmd_direct_mode = 0;
int fast_wdr_mode = 0;
int dual_sensor_mode = 0;
int wdrbuf_len = 0;
int ncu_1_buf_len = 0;
int vpuBs_size = 0;
struct fsx_info fsx[CHN_MAX];
struct fsx_info cmd_chnx[CHN_MAX];

char ncubuf[255] = "";
char dualsensorbuf[255] = "";
char cmdline_buf[1024] = "";

static unsigned long parse_num(const char* addr, const char *strs ,int dfv)
{
    char* num_str = strstr(addr, strs);
    if (num_str == NULL) {
        return dfv;
    }
    num_str += strlen(strs);
    return atoi(num_str);
}
/*******************************/
/*frame1*/
struct frames_state{
    int buf_type;
    int step;
};
enum Zbuffer_type{
    CACHE_INTO_FILE = 1,
    CACHE_INTO_RMEM,
    CACHE_INTO_MEM,
    CACHE_INVAL,
};
const char buffer_type[][10] = {"file","rmem","mem"};

enum{
    QBUF = 1,
    STREAM_ON,
    DQBUF,
    STREAM_OFF,
    REQBUF,
};
struct frame_channels_info{
    int enable;
    int width;
    int height;
    int nrvbs;
};
struct frame_channels_info _fci[4];
int IMP_DQbuffer(const char *path, int channel_index, int is_save)
{
    int ret = 0;
    struct v4l2_buffer buf;
    int fd;
    int openTimes = 0x100;
    while (((fd = open("/proc/multi_channel", O_RDWR )) < 0) && (openTimes-- > 0)){
        usleep(10000);
    }
    if (fd < 0) {
        IMP_LOG_ERR(TAG, "Failed to open channel1\n");
    }
    ret = write(fd, &channel_index,sizeof(int));
    if(ret != sizeof(int)){
        IMP_LOG_ERR(TAG, "config frames2 failed(%d)\n",ret);
        return -1;
    }
    memset(&buf, 0, sizeof(struct v4l2_buffer));
    ret = ioctl(fd, channel_index, &buf);
    if(ret == -2){
        IMP_LOG_ERR(TAG, "%s: TISP_VIDIOC_DQBUF chaneel%d failed\n", __func__,channel_index);
    }
    if(buf.length != 0 && is_save){
        uint32_t devmem_base_vaddr = 0;
        uint32_t devmem_base_paddr = 0;
        uint32_t devmem_base_length = 0;
        int devmem_fd = -1;
        int path_fd = -1;
        devmem_fd = open("/dev/rmem", O_RDWR|O_SYNC);
        if(devmem_fd < 0) {
            return -1;
        }

        devmem_base_paddr = buf.m.userptr;
        devmem_base_length = buf.length;
        IMP_LOG_INFO(TAG,"[chn%d]:%x %x\n",channel_index, devmem_base_paddr,devmem_base_length);
        devmem_base_vaddr = (uint32_t)mmap(NULL, devmem_base_length, PROT_READ|PROT_WRITE, MAP_SHARED, devmem_fd, devmem_base_paddr);
        if (MAP_FAILED == (void*)devmem_base_vaddr) {
            perror("mmap");
            close(devmem_fd);
            return -1;
        }
        path_fd = open(path, O_RDWR | O_SYNC |  O_CREAT, 0664);
        if(path_fd < 0) {
            return -1;
        }
        ret = write(path_fd, devmem_base_vaddr, devmem_base_length);
        if(ret != devmem_base_length){
            printf("write not match\n");
            return -1;
        }
        if (munmap((void*)devmem_base_vaddr, devmem_base_length) == -1)
            IMP_LOG_ERR(TAG, "error:(%s,%d),munmap failed\n",__func__,__LINE__);
        close(devmem_fd);
        close(path_fd);
    }
    close(fd);
    return 0;
}

static int IMP_Get_Channels(void)
{
    char *p = NULL;
	/*check cmdline parameter*/
    //get frame1 info
    struct frames_state frame_channel1;
    {
        int ret = 0;
        int index = 1;
        int fd = open("/proc/multi_channel",O_RDWR);
        if(fd < 0) {
            IMP_LOG_ERR(TAG, "open frames1 failed\n");
            return -1;
        }
        ret = write(fd,&index,sizeof(int));
        if(ret != sizeof(int)){
            IMP_LOG_ERR(TAG, "write frames1 failed(%d)\n",ret);
            return -1;
        }
        ret = read(fd, &frame_channel1, sizeof(struct frames_state));
        if(ret != sizeof(struct frames_state)){
            IMP_LOG_ERR(TAG, "read frames1 failed\n");
            return -1;
        }
        close(fd);

    }

    if(fsx[MAIN_SENSOR_CHN1].total_size){
        if(frame_channel1.buf_type == CACHE_INTO_FILE){
            int i = 0;
            char path[64] = "";
            for(i = 0; i < fsx[MAIN_SENSOR_CHN1].nrvbs;i++){
                sprintf(path,"/tmp/%dx%d-chn%d-%d.yuv", fsx[MAIN_SENSOR_CHN1].width, fsx[MAIN_SENSOR_CHN1].height, MAIN_SENSOR_CHN1, i);
                printf("snap %s\n",path);
                IMP_DQbuffer(path,MAIN_SENSOR_CHN1, 1);
            }
            //close alloc vbmpoll
            fsx[MAIN_SENSOR_CHN1].advance_alloc_enable = 0;
        }
        if(frame_channel1.buf_type == CACHE_INTO_MEM){
            int i = 0;
            for(i = 0; i < fsx[MAIN_SENSOR_CHN1].nrvbs;i++){
                IMP_DQbuffer(NULL, MAIN_SENSOR_CHN1, 0);
            }
            fsx[MAIN_SENSOR_CHN1].advance_alloc_enable = 0;
        }
    }
    //get frame2 info
    struct frames_state frame_channel2;
    {
        int ret = 0;
        int index = 1;
        int fd = open("/proc/multi_channel",O_RDWR);
        if(fd < 0) {
            IMP_LOG_ERR(TAG, "open frames2 failed\n");
            return -1;
        }
        ret = write(fd,&index,sizeof(int));
        if(ret != sizeof(int)){
            IMP_LOG_ERR(TAG, "write frames2 failed(%d)\n",ret);
            return -1;
        }
        ret = read(fd, &frame_channel2, sizeof(struct frames_state));
        if(ret != sizeof(struct frames_state)){
            IMP_LOG_ERR(TAG, "read frames2 failed\n");
            return -1;
        }
        close(fd);
    }
    if(fsx[MAIN_SENSOR_CHN2].total_size){
        if(frame_channel2.buf_type == CACHE_INTO_FILE){
            int i = 0;
            char path[64] = "";
            for(i = 0; i < fsx[MAIN_SENSOR_CHN2].nrvbs;i++){
                sprintf(path,"/tmp/%dx%d-chn%d-%d.yuv", fsx[MAIN_SENSOR_CHN2].width, fsx[MAIN_SENSOR_CHN2].height, MAIN_SENSOR_CHN2, i);
                printf("snap %s\n",path);
                IMP_DQbuffer(path, MAIN_SENSOR_CHN2, 1);
            }
            //close alloc vbmpoll
            fsx[MAIN_SENSOR_CHN2].advance_alloc_enable = 0;
        }
        if(frame_channel2.buf_type == CACHE_INTO_MEM){
            int i = 0;
            for(i = 0; i < fsx[MAIN_SENSOR_CHN2].nrvbs;i++){
                IMP_DQbuffer(NULL, MAIN_SENSOR_CHN2, 0);
            }
            fsx[MAIN_SENSOR_CHN2].advance_alloc_enable = 0;
        }
    }

    //get frame4 info
    struct frames_state frame_channel4;
    {
        int ret = 0;
        int index = 1;
        int fd = open("/proc/multi_channel",O_RDWR);
        if(fd < 0) {
            IMP_LOG_ERR(TAG, "open frames4 failed\n");
            return -1;
        }
        ret = write(fd,&index,sizeof(int));
        if(ret != sizeof(int)){
            IMP_LOG_ERR(TAG, "write frames4 failed(%d)\n",ret);
            return -1;
        }
        ret = read(fd, &frame_channel4, sizeof(struct frames_state));
        if(ret != sizeof(struct frames_state)){
            IMP_LOG_ERR(TAG, "read frames4 failed\n");
            return -1;
        }
        close(fd);

    }

    if(fsx[SEC_SENSOR_CHN4].total_size){
        if(frame_channel4.buf_type == CACHE_INTO_FILE){
            int i = 0;
            char path[64] = "";
            for(i = 0; i < fsx[SEC_SENSOR_CHN4].nrvbs;i++){
                sprintf(path,"/tmp/%dx%d-chn%d-%d.yuv", fsx[SEC_SENSOR_CHN4].width, fsx[SEC_SENSOR_CHN4].height, SEC_SENSOR_CHN4, i);
                printf("snap %s\n",path);
                IMP_DQbuffer(path,SEC_SENSOR_CHN4, 1);
            }
            //close alloc vbmpoll
            fsx[SEC_SENSOR_CHN4].advance_alloc_enable = 0;
        }
        if(frame_channel4.buf_type == CACHE_INTO_MEM){
            int i = 0;
            for(i = 0; i < fsx[SEC_SENSOR_CHN4].nrvbs;i++){
                IMP_DQbuffer(NULL, SEC_SENSOR_CHN4, 0);
            }
            fsx[SEC_SENSOR_CHN4].advance_alloc_enable = 0;
        }
    }

   IMP_LOG_INFO(TAG,"FS1 buffer (%dx%dx%d)%s, FS2 buffer (%dx%dx%d)%s, FS4 buffer (%dx%dx%d)%s\n",
                 fsx[MAIN_SENSOR_CHN1].width, fsx[MAIN_SENSOR_CHN1].height, fsx[MAIN_SENSOR_CHN1].nrvbs,
                 (buffer_type[frame_channel1.buf_type]),
                 fsx[MAIN_SENSOR_CHN2].width, fsx[MAIN_SENSOR_CHN2].height, fsx[MAIN_SENSOR_CHN2].nrvbs,
                 (buffer_type[frame_channel2.buf_type]),
                 fsx[SEC_SENSOR_CHN4].width, fsx[SEC_SENSOR_CHN4].height, fsx[SEC_SENSOR_CHN4].nrvbs,
                 (buffer_type[frame_channel4.buf_type]));

    return 0;
}
/*******************************/

static int IMP_Get_Sensor_WH(void){
    int i = 0;
    char *p = NULL;
    int ret = 0;

    memset(ncubuf,0,255);
    memset(dualsensorbuf,0,255);
    memset(cmdline_buf,0,1024);

    FILE *fdn = fopen("/proc/ncubuf_len", "r");
    if(fdn == NULL) {
        IMP_LOG_ERR(TAG, "open ncubuf_len failed\n");
        return -1;
    }
    fread(ncubuf, sizeof(ncubuf), 1, fdn);
    fclose(fdn);
    char *qn = strstr(ncubuf, "len=");
    if(qn == NULL) {
        IMP_LOG_ERR(TAG, "not match ncu len parameter\n");
        return -1;
    }
    ncubuf_len = atoi((qn+strlen("len=")));
    /*check 2 camera wdr mode parameter*/
    char wdrbuf[255] = "";
    FILE *fd_wdr = fopen("/proc/wdrbuf_len", "r");
    if (fd_wdr == NULL)
        fast_wdr_mode = 0;
    else {
        fast_wdr_mode = 1;
        fread(wdrbuf, sizeof(wdrbuf), 1, fd_wdr);
        fclose(fd_wdr);
        char *q_wdr = strstr(wdrbuf, "len=");
        if (q_wdr == NULL) {
            IMP_LOG_ERR(TAG, "not match wdr len parameter\n");
            return -1;
        }
        wdrbuf_len = atoi((q_wdr+strlen("len=")));
    }

    /*check dual sensor mode parameter*/
    FILE *fdd = fopen("/proc/dual_sensor_buf_len", "r");
    if(fdd == NULL) {
        dual_sensor_mode = 0;
        IMP_LOG_ERR(TAG, "open dual_sensor_buf_len failed, this is single sensor mode\n");
        //return -1;
    }else {
        dual_sensor_mode = 1;
        IMP_LOG_ERR(TAG, "This is dual sensor mode\n");
    }

    if (dual_sensor_mode == 1) {
        char ncu_1_buf[255] = "";
        FILE *fdn1 = fopen("/proc/ncu_1_buf_len", "r");
        if(fdn1 == NULL) {
            IMP_LOG_ERR(TAG, "open ncu_1_buf_len failed\n");
            return -1;
        }
        fread(ncu_1_buf, sizeof(ncu_1_buf), 1, fdn1);
        fclose(fdn1);
        char *qn1 = strstr(ncu_1_buf, "len=");
        if(qn1 == NULL) {
            IMP_LOG_ERR(TAG, "not match ncu_1 len parameter\n");
            return -1;
        }
        ncu_1_buf_len = atoi((qn1+strlen("len=")));
    }

    int fd = open("/proc/vpuBs", O_RDWR);
    if(fd == -1){
        IMP_LOG_ERR(TAG, "[%s %d ] open vpuBs failed. \n");
        return -1;
    }
    ret = read(fd, &vpuBs_size, sizeof(int));
    if(ret < 0){
        IMP_LOG_ERR(TAG, "[%s %d ] read vpuBs size failed. \n");
        return -1;
    }
    close(fd);

    /*check cmdline parameter*/
    FILE *fb = fopen("/proc/cmdline", "r");
    if(fb == NULL) {
        IMP_LOG_ERR(TAG, "open cmdline failed\n");
        return -1;
    }

    fread(cmdline_buf, sizeof(cmdline_buf), 1, fb);
    fclose(fb);

    memset(&fsx, 0, sizeof(struct fsx_info) * CHN_MAX);
    //get cmdline chn info
    fsx[MAIN_SENSOR_CHN0].width  = parse_num(cmdline_buf, "init_vw=", 0);
    fsx[MAIN_SENSOR_CHN0].height = parse_num(cmdline_buf, "init_vh=", 0);
    fsx[MAIN_SENSOR_CHN0].nrvbs  = parse_num(cmdline_buf, "nrvbs=", 0);
    memcpy(&cmd_chnx[MAIN_SENSOR_CHN0], &fsx[MAIN_SENSOR_CHN0], sizeof(struct fsx_info));

    fsx[MAIN_SENSOR_CHN1].width  = parse_num(cmdline_buf, "init_vw_chn1=", 0);
    fsx[MAIN_SENSOR_CHN1].height = parse_num(cmdline_buf,"init_vh_chn1=", 0);
    fsx[MAIN_SENSOR_CHN1].nrvbs  = parse_num(cmdline_buf, "nrvbs_chn1=", 0);
    memcpy(&cmd_chnx[MAIN_SENSOR_CHN1], &fsx[MAIN_SENSOR_CHN1], sizeof(struct fsx_info));

    fsx[MAIN_SENSOR_CHN2].width  = parse_num(cmdline_buf, "init_vw_chn2=", 0);
    fsx[MAIN_SENSOR_CHN2].height = parse_num(cmdline_buf, "init_vh_chn2=", 0);
    fsx[MAIN_SENSOR_CHN2].nrvbs  = parse_num(cmdline_buf, "nrvbs_chn2=", 0);
    memcpy(&cmd_chnx[MAIN_SENSOR_CHN2], &fsx[MAIN_SENSOR_CHN2], sizeof(struct fsx_info));

    for(i = MAIN_SENSOR_CHN0;i<= MAIN_SENSOR_CHN2;i++){
        if(fsx[i].height != ((fsx[i].height + 0xf) & (~0xf))){
            fsx[i].height = (fsx[i].height + 0xf) & (~0xf);
        }
        fsx[i].total_size = fsx[i].height * fsx[i].width * fsx[i].nrvbs * 3 / 2 ;
    }


    cmd_direct_mode = parse_num(cmdline_buf, "direct_mode_save_kernel_ch1=", 0);

    if(dual_sensor_mode == 1){
        fsx[SEC_SENSOR_CHN3].width  = parse_num(cmdline_buf,  "sub_init_vw=", 0);
        fsx[SEC_SENSOR_CHN3].height = parse_num(cmdline_buf,  "sub_init_vh=", 0);
        fsx[SEC_SENSOR_CHN3].nrvbs  = parse_num(cmdline_buf,  "sub_nrvbs=", 0);
        memcpy(&cmd_chnx[SEC_SENSOR_CHN3], &fsx[SEC_SENSOR_CHN3], sizeof(struct fsx_info));

        fsx[SEC_SENSOR_CHN4].width  = parse_num(cmdline_buf,  "sub_init_vw_chn4=", 0);
        fsx[SEC_SENSOR_CHN4].height = parse_num(cmdline_buf,  "sub_init_vh_chn4=", 0);
        fsx[SEC_SENSOR_CHN4].nrvbs  = parse_num(cmdline_buf,  "sub_nrvbs_chn4=", 0);
        memcpy(&cmd_chnx[SEC_SENSOR_CHN4], &fsx[SEC_SENSOR_CHN4], sizeof(struct fsx_info));

        fsx[SEC_SENSOR_CHN5].width  = parse_num(cmdline_buf,  "sub_init_vw_chn5=", 0);
        fsx[SEC_SENSOR_CHN5].height = parse_num(cmdline_buf,  "sub_init_vh_chn5=", 0);
        fsx[SEC_SENSOR_CHN5].nrvbs  = parse_num(cmdline_buf,  "sub_nrvbs_chn5=", 0);
        memcpy(&cmd_chnx[SEC_SENSOR_CHN5], &fsx[SEC_SENSOR_CHN5], sizeof(struct fsx_info));

        for(i = SEC_SENSOR_CHN3;i<= SEC_SENSOR_CHN5;i++){
            if(fsx[i].height != ((fsx[i].height + 0xf) & (~0xf))){
                fsx[i].height = (fsx[i].height + 0xf) & (~0xf);
            }
            fsx[i].total_size = fsx[i].height * fsx[i].width * fsx[i].nrvbs * 3 / 2 ;
        }
    }

    //check
    if(fsx[MAIN_SENSOR_CHN0].nrvbs <= 0) {
        g_VBMPoolx_alloc_flag[0] = 0;
    }
    if(fsx[MAIN_SENSOR_CHN1].nrvbs <= 0){
        g_VBMPoolx_alloc_flag[1] = 0;
    }

    if(fsx[SEC_SENSOR_CHN3].nrvbs <=0 && dual_sensor_mode == 1) {
        g_VBMPoolx_alloc_flag[3] = 0;
    }

    if(fsx[SEC_SENSOR_CHN4].nrvbs && dual_sensor_mode == 1){
        g_VBMPoolx_alloc_flag[4] = 0;
    }

    for(i = MAIN_SENSOR_CHN0; i < CHN_MAX; i++){
        if(fsx[i].total_size){
            fsx[i].advance_alloc_enable = 1;
        }
    }
    //check ivdc status
    int fast_direct_status = 0;
    int ivdc_fd = open("/dev/misc-ivdc", O_RDONLY);
    if (ivdc_fd < 0) {
        IMP_LOG_ERR(TAG,"open misc-ivdc failed\n");
        return -1;
    }
    ret = ioctl(ivdc_fd, TISP_VIDIOC_GET_DIRECT, &fast_direct_status);
    if (ret < 0) {
        IMP_LOG_ERR(TAG, "%s(%d): TISP_VIDIOC_GET_DIRECT failed\n", __func__, __LINE__);
        return -1;
    }
    close(ivdc_fd);
    //close chn0 vbm in ivdc mode
    if(fast_direct_status){
        fsx[0].advance_alloc_enable = 0;
        fsx[3].advance_alloc_enable = 0;
    }
    IMP_LOG_INFO(TAG,"FS0(%dx%dx%d) %s,FS1(%dx%dx%d) %s,FS2(%dx%dx%d) %s,FS3(%dx%dx%d) %s,FS4(%dx%dx%d) %s,FS5(%dx%dx%d) %s\n",
                 cmd_chnx[MAIN_SENSOR_CHN0].width, cmd_chnx[MAIN_SENSOR_CHN0].height, cmd_chnx[MAIN_SENSOR_CHN0].nrvbs, fsx[0].advance_alloc_enable ? "enable" : "disable",
                 cmd_chnx[MAIN_SENSOR_CHN1].width, cmd_chnx[MAIN_SENSOR_CHN1].height, cmd_chnx[MAIN_SENSOR_CHN1].nrvbs, fsx[1].advance_alloc_enable ? "enable" : "disable",
                 cmd_chnx[MAIN_SENSOR_CHN2].width, cmd_chnx[MAIN_SENSOR_CHN2].height, cmd_chnx[MAIN_SENSOR_CHN2].nrvbs, fsx[2].advance_alloc_enable ? "enable" : "disable",
                 cmd_chnx[SEC_SENSOR_CHN3].width,  cmd_chnx[SEC_SENSOR_CHN3].height,  cmd_chnx[SEC_SENSOR_CHN3].nrvbs,  fsx[3].advance_alloc_enable ? "enable" : "disable",
                 cmd_chnx[SEC_SENSOR_CHN4].width,  cmd_chnx[SEC_SENSOR_CHN4].height,  cmd_chnx[SEC_SENSOR_CHN4].nrvbs,  fsx[4].advance_alloc_enable ? "enable" : "disable",
                 cmd_chnx[SEC_SENSOR_CHN5].width,  cmd_chnx[SEC_SENSOR_CHN5].height,  cmd_chnx[SEC_SENSOR_CHN5].nrvbs,  fsx[5].advance_alloc_enable ? "enable" : "disable" );
    return 0;
}
#endif

static int IMP_init()
{
    if(g_alloc.init_status == ALLOC_ALREADY_INITIALIZED)
        return 0;

    sprintf(g_alloc.mem_alloc.method, MEM_ALLOC_METHOD);
    sprintf(g_alloc.mem_manager.method, MEM_MANAGER_METHOD);

    int ret = allocInit(&g_alloc);
    if(ret != 0) {
        IMP_LOG_ERR(TAG, "alloc init failed\n");
    }

#if ZRT_Platform && FASTSTART_EN
    /*For Zeratul*/
    if(0 != IMP_Get_Sensor_WH()) {
        return ret;
    }
    IMP_Get_Channels();

    ncubuf_len = (ncubuf_len + 0xF) & (~0xF);
    ret = IMP_Alloc(&g_ncubuf_alloc, ncubuf_len, "Rncubuf");
    if (ret != 0) {
        IMP_LOG_ERR(TAG, "alloc ncubuf failed\n");
        g_ncubuf_alloc_flag = 0;
    } else {
        g_ncubuf_alloc_flag = 1;
    }

    if (dual_sensor_mode == 1){
        ncu_1_buf_len = (ncu_1_buf_len + 0xF) & (~0xF);
        ret = IMP_Alloc(&g_ncu_1_buf_alloc, ncu_1_buf_len, "Rncubuf-1");
        if (ret != 0) {
            IMP_LOG_ERR(TAG, "alloc ncu_1_buf failed\n");
            g_ncu_1_buf_alloc_flag = 0;
        } else {
            g_ncu_1_buf_alloc_flag = 1;
        }
    }

    if (fast_wdr_mode == 1) {
        wdrbuf_len = (wdrbuf_len + 0xF) & (~0xF);
        ret = IMP_Alloc(&g_wdrbuf_alloc, wdrbuf_len, "Rwdrbuf");
        if(ret != 0) {
            IMP_LOG_ERR(TAG, "alloc wdr buf failed\n");
            g_wdrbuf_alloc_flag = 0;
        } else {
            g_wdrbuf_alloc_flag = 1;
        }
    }
    //main sensor stream0
    if(cmd_direct_mode == 0){
        if(fsx[MAIN_SENSOR_CHN0].advance_alloc_enable){
            ret = IMP_Alloc(&g_VBMPoolx_alloc[MAIN_SENSOR_CHN0], fsx[MAIN_SENSOR_CHN0].total_size, "RVBMPool0");
            if(ret != 0) {
                IMP_LOG_ERR(TAG, "alloc init failed\n");
                g_VBMPoolx_alloc_flag[MAIN_SENSOR_CHN0] = 0;
            } else {
                g_VBMPoolx_alloc_flag[MAIN_SENSOR_CHN0] = 1;
            }
        }
    }

    //alloc vpuBs
    ret = IMP_Alloc(&g_vpuBs_alloc, vpuBs_size, "RvpuBs");
    if (ret != 0) {
        IMP_LOG_ERR(TAG, "%s %d alloc vpuBs failed\n", __func__, __LINE__);
        g_vpuBs_alloc_flag = 0;
    } else {
        g_vpuBs_alloc_flag = 1;
        IMP_LOG_INFO(TAG,"RvpuBs size:%d \n", vpuBs_size);
    }

    //main sensor stream1
    if(fsx[MAIN_SENSOR_CHN1].advance_alloc_enable){
        ret = IMP_Alloc(&g_VBMPoolx_alloc[MAIN_SENSOR_CHN1], fsx[MAIN_SENSOR_CHN1].total_size, "RVBMPool1");
        if(ret != 0) {
            IMP_LOG_ERR(TAG, "alloc init failed\n");
            g_VBMPoolx_alloc_flag[MAIN_SENSOR_CHN1] = 0;
        } else {
            g_VBMPoolx_alloc_flag[MAIN_SENSOR_CHN1] = 1;
        }
    }
    //main sensor stream2
    if(fsx[MAIN_SENSOR_CHN2].advance_alloc_enable){
        ret = IMP_Alloc(&g_VBMPoolx_alloc[MAIN_SENSOR_CHN2], fsx[MAIN_SENSOR_CHN2].total_size, "RVBMPool2");
        if(ret != 0) {
            IMP_LOG_ERR(TAG, "alloc init failed\n");
            g_VBMPoolx_alloc_flag[MAIN_SENSOR_CHN2] = 0;
        } else {
            g_VBMPoolx_alloc_flag[MAIN_SENSOR_CHN2] = 1;
        }
    }

    if (dual_sensor_mode == 1){
        if(cmd_direct_mode == 0){
            if(fsx[SEC_SENSOR_CHN3].advance_alloc_enable){
                ret = IMP_Alloc(&g_VBMPoolx_alloc[SEC_SENSOR_CHN3], fsx[SEC_SENSOR_CHN3].total_size, "RVBMPool3");
                if(ret != 0) {
                    IMP_LOG_ERR(TAG, "alloc init failed\n");
                    g_VBMPoolx_alloc_flag[SEC_SENSOR_CHN3] = 0;
                } else {
                    g_VBMPoolx_alloc_flag[SEC_SENSOR_CHN3] = 1;
                }
            }
        }
        if(fsx[SEC_SENSOR_CHN4].advance_alloc_enable){
            ret = IMP_Alloc(&g_VBMPoolx_alloc[SEC_SENSOR_CHN4], fsx[SEC_SENSOR_CHN4].total_size, "RVBMPool4");
            if(ret != 0) {
                IMP_LOG_ERR(TAG, "alloc init failed\n");
                g_VBMPoolx_alloc_flag[SEC_SENSOR_CHN4] = 0;
            } else {
                g_VBMPoolx_alloc_flag[SEC_SENSOR_CHN4] = 1;
            }
        }
    }

    //IMP_Alloc_Dump();
    IMP_Alloc_Dump_To_File();
#endif

    return ret;
}

static int IMP_Get_Info(IMPAlloc *alloc, void *ptr)
{
    if(alloc == NULL || ptr == NULL) {
        IMP_LOG_ERR(TAG, "%s IMPAlloc *alloc == NULL or ptr == NULL\n", __func__);
        return -1;
    }

    if(IMP_init()) {
        IMP_LOG_ERR(TAG, "imp init failed\n");
        return -1;
    }

    if(g_alloc.getAllocInfo) {
        AllocInfo *info = g_alloc.getAllocInfo(&g_alloc, ptr);
        if(info == NULL) {
            IMP_LOG_ERR(TAG, "get alloc info error\n");
            return -1;
        }
        strncpy(alloc->info.owner, info->owner, sizeof(alloc->info.owner) - 1);
        alloc->info.vaddr = info->vaddr;
        alloc->info.paddr = info->paddr;
        alloc->info.length = info->length;
        alloc->info.ref_cnt = info->ref_cnt;
        alloc->info.mem_attr = info->mem_attr;
    }

    return 0;
}

int IMP_Alloc(IMPAlloc *alloc, int size, char *owner)
{
    void *addr = NULL;

    if(alloc == NULL) {
        IMP_LOG_ERR(TAG, "IMPAlloc *alloc = NULL\n");
        return -1;
    }

    if(IMP_init()) {
        IMP_LOG_ERR(TAG, "imp init failed\n");
        return -1;
    }
    IMP_LOG_INFO(TAG,"Owner %s\n",owner);

#if ZRT_Platform && FASTSTART_EN
    /*For Zeratul*/
    if (g_ncubuf_alloc_flag && (strcmp(owner, "ncubuf-0") == 0)) {
        IMP_LOG_INFO(TAG, "%s alloc use g_ncubuf-0\n",owner);
        memcpy(alloc, &g_ncubuf_alloc, sizeof(IMPAlloc));
        return 0;
    }

    if (dual_sensor_mode == 1) {
        if (g_ncu_1_buf_alloc_flag && (strcmp(owner, "ncubuf-1") == 0)) {
            IMP_LOG_INFO(TAG, "%s alloc use g_ncubuf-1\n",owner);
            memcpy(alloc, &g_ncu_1_buf_alloc, sizeof(IMPAlloc));
            return 0;
        }
    }

    if (fast_wdr_mode == 1) {
        if(g_wdrbuf_alloc_flag && (strcmp(owner, "wdrbuf") == 0)) {
            IMP_LOG_ERR(TAG, "%s alloc use g_wdrbuf_alloc\n",owner);
            memcpy(alloc, &g_wdrbuf_alloc, sizeof(IMPAlloc));
            return 0;
        }
    }

    if (g_vpuBs_alloc_flag && (strcmp(owner, "vpuBs") == 0)) {
        IMP_LOG_INFO(TAG, "%s alloc use g_vpuBs\n",owner);
        memcpy(alloc, &g_vpuBs_alloc, sizeof(IMPAlloc));
        return 0;
    }

    if(g_VBMPoolx_alloc_flag[MAIN_SENSOR_CHN0] && (strcmp(owner, "VBMPool0") == 0)) {
        IMP_LOG_INFO(TAG, "%s alloc use g_VBMPool0_alloc\n", owner);
        memcpy(alloc, &g_VBMPoolx_alloc[MAIN_SENSOR_CHN0], sizeof(IMPAlloc));
        return 0;
    }
    if(g_VBMPoolx_alloc_flag[MAIN_SENSOR_CHN1] && (strcmp(owner, "VBMPool1") == 0)) {
        IMP_LOG_INFO(TAG, "%s alloc use g_VBMPool1_alloc\n", owner);
        memcpy(alloc, &g_VBMPoolx_alloc[MAIN_SENSOR_CHN1], sizeof(IMPAlloc));
        return 0;
    }
    if(g_VBMPoolx_alloc_flag[MAIN_SENSOR_CHN2] && (strcmp(owner, "VBMPool2") == 0)) {
        IMP_LOG_INFO(TAG, "%s alloc use g_VBMPool2_alloc\n", owner);
        memcpy(alloc, &g_VBMPoolx_alloc[MAIN_SENSOR_CHN2], sizeof(IMPAlloc));
        return 0;
    }

    if (dual_sensor_mode == 1) {
        if(g_VBMPoolx_alloc_flag[SEC_SENSOR_CHN3] && (strcmp(owner, "VBMPool3") == 0)) {
            IMP_LOG_INFO(TAG, "%s alloc use g_VBMPool3_alloc\n", owner);
            memcpy(alloc, &g_VBMPoolx_alloc[SEC_SENSOR_CHN3], sizeof(IMPAlloc));
            return 0;
        }
        if(g_VBMPoolx_alloc_flag[SEC_SENSOR_CHN4] && (strcmp(owner, "VBMPool4") == 0)) {
            IMP_LOG_INFO(TAG, "%s alloc use g_VBMPool4_alloc\n", owner);
            memcpy(alloc, &g_VBMPoolx_alloc[SEC_SENSOR_CHN4], sizeof(IMPAlloc));
            return 0;
        }
    }

#endif

    if(g_alloc.alloc_mem) {
        addr = g_alloc.alloc_mem(&g_alloc, size, owner);
        if(addr == NULL) {
            IMP_LOG_ERR(TAG, "g_alloc.alloc_mem failed\n");
            IMP_Alloc_Dump();
            return -1;
        }
        if(IMP_Get_Info(alloc, addr)) {
            IMP_LOG_ERR(TAG, "IMP_Get_info failed\n");
            IMP_Alloc_Dump();
            return -1;
        }
    }

    IMP_Alloc_Dump_To_File();
    return 0;
}

int IMP_Sp_Alloc(IMPAlloc *alloc, void *ptr)
{
    void *addr = NULL;

    if(alloc == NULL || ptr == NULL) {
        IMP_LOG_ERR(TAG, "IMPAlloc *alloc == NULL or ptr == NULL\n");
        return -1;
    }

    if(IMP_init()) {
        IMP_LOG_ERR(TAG, "imp init failed\n");
        return -1;
    }

    if(g_alloc.sp_alloc_mem) {
        addr = g_alloc.sp_alloc_mem(&g_alloc, ptr);
        if(addr == NULL) {
            IMP_LOG_ERR(TAG, "g_alloc.alloc_mem failed\n");
            return -1;
        }
        if(IMP_Get_Info(alloc, addr)) {
            IMP_LOG_ERR(TAG, "IMP_Get_info failed\n");
            return -1;
        }
    }

    IMP_Alloc_Dump_To_File();
    return 0;
}

void IMP_Free(IMPAlloc *alloc, void *ptr)
{
    if(alloc == NULL || ptr == NULL) {
        IMP_LOG_ERR(TAG, "IMPAlloc *alloc == NULL or ptr == NULL\n");
        return;
    }

    if(IMP_init()) {
        IMP_LOG_ERR(TAG, "imp init failed\n");
        return;
    }

#if ZRT_Platform && FASTSTART_EN
    /*For Zeratul*/
    if(g_ncubuf_alloc_flag && alloc->info.vaddr == g_ncubuf_alloc.info.vaddr) {
        IMP_LOG_INFO(TAG, "%s free g_ncubuf_alloc\n", alloc->info.owner);
        return;
    }

    if(g_vpuBs_alloc_flag && alloc->info.vaddr == g_vpuBs_alloc.info.vaddr) {
        IMP_LOG_INFO(TAG, "%s free g_vpuBs_alloc\n", alloc->info.owner);
        return;
    }

    if(g_VBMPoolx_alloc_flag[MAIN_SENSOR_CHN0] && alloc->info.vaddr == g_VBMPoolx_alloc[MAIN_SENSOR_CHN0].info.vaddr) {
        IMP_LOG_INFO(TAG, "%s free g_VBMPool0_alloc\n", alloc->info.owner);
        return;
    }

    if(g_VBMPoolx_alloc_flag[MAIN_SENSOR_CHN1] && alloc->info.vaddr == g_VBMPoolx_alloc[MAIN_SENSOR_CHN1].info.vaddr) {
        IMP_LOG_INFO(TAG, "%s free g_VBMPool1_alloc\n", alloc->info.owner);
        return;
    }

    if(g_VBMPoolx_alloc_flag[MAIN_SENSOR_CHN2] && alloc->info.vaddr == g_VBMPoolx_alloc[MAIN_SENSOR_CHN2].info.vaddr) {
        IMP_LOG_INFO(TAG, "%s free g_VBMPool2_alloc\n", alloc->info.owner);
        return;
    }

    if (dual_sensor_mode == 1) {
        if(g_ncu_1_buf_alloc_flag && alloc->info.vaddr == g_ncu_1_buf_alloc.info.vaddr) {
            IMP_LOG_INFO(TAG, "%s free g_ncubuf1_alloc\n", alloc->info.owner);
            return;
        }

        if(g_VBMPoolx_alloc_flag[SEC_SENSOR_CHN3] && alloc->info.vaddr == g_VBMPoolx_alloc[SEC_SENSOR_CHN3].info.vaddr) {
            IMP_LOG_INFO(TAG, "%s free g_VBMPool3_alloc\n", alloc->info.owner);
            return;
        }
        if(g_VBMPoolx_alloc_flag[SEC_SENSOR_CHN4] && alloc->info.vaddr == g_VBMPoolx_alloc[SEC_SENSOR_CHN4].info.vaddr) {
            IMP_LOG_INFO(TAG, "%s free g_VBMPool4_alloc\n", alloc->info.owner);
            return;
        }
    }
#endif

    if(g_alloc.free_mem) {
        if(IMP_Get_Info(alloc, ptr)) {
            IMP_LOG_ERR(TAG, "IMP_Get_info failed\n");
            return;
        }
        g_alloc.free_mem(&g_alloc, ptr);
        alloc->info.ref_cnt -= 1;
        if(alloc->info.ref_cnt == 0) {
            alloc->info.vaddr = 0;
            alloc->info.paddr = 0;
        }
    }

    IMP_Alloc_Dump_To_File();
}

IMPMemAttr IMP_Alloc_Get_Attr(IMPAlloc *alloc)
{
    if(alloc == NULL) {
        IMP_LOG_ERR(TAG, "IMPAlloc *alloc == NULL\n");
        return -1;
    }

    if(IMP_init()) {
        IMP_LOG_ERR(TAG, "imp init failed\n");
        return -1;
    }

    if(g_alloc.get_mem_attr) {
        alloc->info.mem_attr = g_alloc.get_mem_attr(&g_alloc, (void *)alloc->info.vaddr);
    }

    return alloc->info.mem_attr;
}

int IMP_Alloc_Set_Attr(IMPAlloc *alloc)
{
    int ret = 0;
    if(alloc == NULL) {
        IMP_LOG_ERR(TAG, "IMPAlloc *alloc == NULL\n");
        return -1;
    }

    if(IMP_init()) {
        IMP_LOG_ERR(TAG, "imp init failed\n");
        return -1;
    }

    if(g_alloc.set_mem_attr) {
        ret = g_alloc.set_mem_attr(&g_alloc,
                                   (void *)alloc->info.vaddr, alloc->info.mem_attr);
    }

    return ret;
}

void IMP_Alloc_Dump()
{
    if(IMP_init()) {
        IMP_LOG_ERR(TAG, "imp init failed\n");
        return;
    }

    if(g_alloc.dump_mem_status)
        g_alloc.dump_mem_status(&g_alloc);
}

void IMP_Alloc_Dump_To_File()
{
    if(IMP_init()) {
        IMP_LOG_ERR(TAG, "imp init failed\n");
        return;
    }

    if(g_alloc.dump_mem_to_file)
        g_alloc.dump_mem_to_file(&g_alloc);
}


void *IMP_Virt_to_Phys(void *vaddr)
{
    if(IMP_init()) {
        IMP_LOG_ERR(TAG, "imp init failed\n");
        return NULL;
    }

    if(g_alloc.mem_alloc.get_paddr)
        return (void *)g_alloc.mem_alloc.get_paddr((uint32_t)vaddr);
    return NULL;
}

void *IMP_Phys_to_Virt(void *paddr)
{
    if(IMP_init()) {
        IMP_LOG_ERR(TAG, "imp init failed\n");
        return NULL;
    }

    if(g_alloc.mem_alloc.get_vaddr)
        return (void *)g_alloc.mem_alloc.get_vaddr((uint32_t)paddr);
    return NULL;
}

int IMP_FlushCache(void *vaddr, size_t size, uint32_t dir)
{
    if(IMP_init()) {
        IMP_LOG_ERR(TAG, "imp init failed\n");
        return -1;
    }

    if(g_alloc.mem_alloc.flush_cache)
        return g_alloc.mem_alloc.flush_cache((uint32_t)vaddr, size, dir);
    return -1;
}
